import json
import datetime
import threading
import time
from testapp.dataio.dataiofactory import DataIOFactory
from .methodFactory import MethodFactory
from testapp.common.parameteriZation import replace_data
from testapp.control.ctmanage import CtManage
from urllib import parse







class Runingfac(threading.Thread):
    def __init__(self, exetype, id, env_id=None):
        """
        exetype : 0为用例， 1为计划
        """
        threading.Thread.__init__(self)
        self.datafac = DataIOFactory()
        self.metfac = MethodFactory()
        self.manage = CtManage()
        self.exetype = exetype
        self.id = id
        self.env_id = env_id

    def run(self):
        """
        线程启动
        """
        if self.exetype == 0:
            # print("用例线程开始")
            self.caseExcute(case_id=self.id, env_id=self.env_id)     #执行用例
            # print("用例线程结束")
        elif self.exetype == 1:
            # print("计划线程开始")
            self.planExcute(plan_id=self.id)             #执行计划
            # print("计划线程结束")

    def caseExcute(self, case_id, env_id):
        isOK, result = self.setEvn(env_id)
        if isOK == False:
            return isOK, '设置环境失败，具体原因[{}]'.format(result)

        isOK, result = self.getCase(case_id)
        if isOK:
            report = {}
            report['excutnum'] = -1
            report['planid'] = None
            report['caseid'] = case_id
            report['casename'] = result['apiFrom']['name']
            isOK, result = self.excutCase(result, env_id)
            self.metfac.method_factory(method='ClearParams')
            report['elapsedt'] = result['elapsedt']
            if isOK:
                report['status'] = 1
            else:
                report['status'] = 0
            report['testresult'] =json.dumps(result, sort_keys=True, indent=2, ensure_ascii=False)
            return self.datafac.addTestReport(report)
        else:
            return isOK, '执行用例获取失败，具体原因{}'.format(result)

    def planExcute(self, plan_id):
        isOK, result = self.datafac.getPlanDetail(plan_id)
        # print("获取计划详情完成")
        if isOK:
            planDetail = result
            isOK, result = self.setEvn(planDetail['venid_id'])
            if isOK == False:
                return isOK, '设置环境失败，具体原因[{}]'.format(result)
            # print("设置环境变量完成")
            isOK, result = self.getPlan(plan_id)
            # print("获取计划的用例完成")
            if isOK:
                excutnum = str(datetime.datetime.now().strftime('%Y%m%d%H%M%S')) + str(plan_id) + str(len(result))
                isOK, result = self.excutPlan(result, excutnum, plan_id, planDetail)
                # print("执行计划中用例完成")
                self.metfac.method_factory(method='ClearParams')
                if isOK and planDetail['qymsg'] == 1:
                    isOK, result = self.datafac.getPlanExRecbyNum(excutnum)
                    if isOK:
                        result['planName'] = planDetail['name']
                        result['webhook'] = planDetail['webhook']
                        passRatio = (result['passCount'] / result['caseCount'] * 10000) / 100.00
                        result['passRatio'] = float('%.2f' % passRatio)
                        result['reportUrl'] = 'http://172.56.140.2:5001/planexerep?excutnum={}'.format(excutnum)
                        self.manage.sentQymsg(**result)
                        return True, "执行成功"
                else:
                    return isOK, result
            else:
                return isOK, result
        else:
            return isOK, result


    def getCase(self, case_id):
        return self.datafac.getExcCase(case_id)


    def getPlan(self, plan_id):
        isOK, result = self.datafac.getLinks(plan_id)
        if isOK:
            cases = []
            for link in result:
                isOK, result = self.getCase(link['caseid_id'])
                if isOK:
                    cases.append(result)
                else:
                    return isOK, "执行用例获取失败，具体原因{}".format(result)
        else:
            return isOK, "用例集获取失败，具体原因{}".format(result)
        return True, cases




    def excutCase(self, caseData, envid):
        #执行前置自定义
        caserpe = []
        comrep = []
        sqlrep = []
        parrep = []
        resrep = []
        for sql in caseData['sqlFrom']:
            sql['method'] = '执行SQL'
            sql['envid'] = envid
            isOK, result = self.metfac.method_factory(**sql)
            sqlrep.append(result)

        for pre in caseData['commoFrom']:
            pre['envid'] = envid
            isOK, result = self.metfac.method_factory(**pre)
            comrep.append(result)

        #执行用例
        case = caseData['apiFrom']
        _isOK, result = self.metfac.method_factory(method='Replacedata', data='${host}')
        case['url'] = parse.urljoin(result, case['api'])
        datarep = self.formatCase(case)
        _isOK, result, elapsedt = self.send_api(case)
        caserpe.append(result)
        if _isOK:
            # 执行参数化，成功才有参数化
            for par in caseData['parcommonFrom']:
                isOK, result = self.metfac.method_factory(**par)
                parrep.append(result)

            # 执行后置自定义
            for res in caseData['rescommonFrom']:
                res['envid'] = envid
                isOK, result = self.metfac.method_factory(**res)
                resrep.append(result)
        report = {}
        report['datarep'] = datarep
        report['caserpe'] = caserpe
        report['comrep'] = comrep
        report['sqlrep'] = sqlrep
        report['parrep'] = parrep
        report['resrep'] = resrep
        report['elapsedt'] = elapsedt

        return _isOK, report

    def formatCase(self, case):
        _isOK, case['url'] = self.metfac.method_factory(method='Replacedata', data=case['url'])
        if case['headers'] != '':
            _isOK, case['headers'] = self.metfac.method_factory(method='Replacedata', data=case['headers'])
        if case['body'] != '':
            try:
                _isOK, case['body'] = self.metfac.method_factory(method='Replacedata', data=json.dumps(json.loads(case['body']), sort_keys=False, indent=4, ensure_ascii=False))
            except Exception as e:
                _isOK, case['body'] = self.metfac.method_factory(method='Replacedata', data=case['body'])
        if 'get' == str.lower(case['apimethod']):
            if '?' in str(case['url']):
                url = str(case['url'])
                a, param = url.split('?')
                _isOK, case['data'] = self.metfac.method_factory(method='Replacedata', data=param)
            else:
                case['data'] = ''
        datarep = []
        datarep.append(case)
        return datarep



    def excutPlan(self, planData, excutnum, planid, planDetail):
        caseCount = len(planData)
        passCount = 0
        failCount = 0
        thrCount = 0
        sevCount = 0
        secCount = 0
        totalTime = 0.00
        for case in planData:
            report = {}
            report['excutnum'] = excutnum
            report['planid'] = planid
            report['caseid'] = case['apiFrom']['id']
            report['casename'] = case['apiFrom']['name']
            isOK, result = self.excutCase(case, planDetail['venid_id'])
            report['elapsedt'] = result['elapsedt']
            totalTime += float(result['elapsedt'])
            if float(result['elapsedt']) >= 300 and float(result['elapsedt']) < 500:
                thrCount = thrCount + 1
            elif float(result['elapsedt']) >= 500 and float(result['elapsedt']) < 1000:
                sevCount = sevCount + 1
            elif float(result['elapsedt']) >= 1000:
                secCount = secCount + 1
            if isOK:
                report['status'] = 1
                passCount += 1
            else:
                report['status'] = 0
                failCount += 1
            report['testresult'] = json.dumps(result, sort_keys=True, indent=2, ensure_ascii=False)
            self.datafac.addTestReport(report)
        record = {}
        record['excutnum'] = excutnum
        record['planid'] = planid
        record['caseCount'] = caseCount
        record['passCount'] = passCount
        record['failCount'] = failCount
        record['totalTime'] = float('%.2f' % totalTime)
        record['thrCount'] = thrCount
        record['sevCount'] = sevCount
        record['secCount'] = secCount
        record['planName'] = planDetail['name']
        self.datafac.addPlanRecord(record)
        return True, "执行成功"

    def saveCaseReport(self, caseReport):
        pass

    def savePlanReport(self, planReport):
        pass

    def setEvn(self, envid):
        #设置执行环境
        try:
            isOK, result = self.datafac.getEnvbyID(envid)
            if isOK:
                self.metfac.method_factory(method="设置变量", result='host', f_params=result['url'])
                self.metfac.method_factory(method="设置变量", result='db', f_params=result['db'])
                self.metfac.method_factory(method="设置变量", result='dbuser', f_params=result['dbuser'])
                self.metfac.method_factory(method="设置变量", result='dbpwd', f_params=result['dbpwd'])
                self.metfac.method_factory(method="设置变量", result='dbport', f_params=result['dbport'])
                self.metfac.method_factory(method="设置变量", result='dbname', f_params=result['dbname'])
                self.metfac.method_factory(method="设置变量", result='Global_Toke', f_params=result['global_toke'])
                self.metfac.method_factory(method="设置变量", result='resapi', f_params=result['resapi'])
                return isOK, "设置环境变量成功"
            else:
                return isOK, result
        except Exception as e:
            return False, str(e)


    def send_api(self, case):
        title = case['name']
        if case['checkmethod'] == '' or case['checkdata'] == '':
            checkType = 2
            rules = '等于'
            expect = '200'
        else:
            checkType = case['checkrestype']
            rules = case['checkmethod']
            expect = case['checkdata']

        isOK, result = self.metfac.method_factory(**case)
        if isOK:
            response = result
            timechou = response.elapsed.total_seconds() * 100
            timec = float('%.2f' % timechou)
            elapsedt = str(timec)
            try:
                self.metfac.method_factory(method='设置变量', result='response', f_params=response)  # 返回json存
            except Exception:
                res = response.text
                self.metfac.method_factory(method='设置变量', result='response', f_params=res)  # 返回html 或xml、 txt存

            isOK, _reason = self._assert_res_expr(checkType, rules, response, expect)
            if isOK:
                _strLog = '用例[' + str(case['id']) + ']：[' + title + ']执行通过. \n 校验结果：\n' + _reason
            else:
                _strLog = "用例[" + str(case['id']) + ']：[' + title + ']执行不通过.\n 原因：\n' + _reason
        else:
            _strLog = "用例[" + str(case['id']) + ']：[' + title + ']执行不通过. \n 原因：\ n' + result
            elapsedt = '0'
        return isOK, _strLog, elapsedt



    def _assert_res_expr(self, checktype, rules, reponse, expr):
        """
        断言方法
        :type  校验数据的类型 0是返回头，1是返回数据，2是接口状态
        :param rules:结果包含、结果等于、结果状态
        :param res:
        :param expr:
        :return:
        """
        if(checktype == 0):
            headers = reponse.headers
            if rules == '包含':
                if type(expr) is str:
                    _isOK, expr = self.metfac.method_factory(method='Replacedata', data=expr)
                    headers = json.dumps(dict(headers), ensure_ascii=False)
                    print_header = json.dumps(json.loads(headers), sort_keys=True, indent=2, ensure_ascii=False)
                else:
                    print_header = headers
                try:
                    headers.index(expr)
                except Exception as e:
                    _isOk = False
                    _reason = '结果头:\n【' + print_header + '】\n  不包含校验值:\n 【' + expr + '】\n <-- 校验方式：Response Header ' + rules + ' -->'
                else:
                    _isOk = True
                    _reason = '结果头:\n【' + print_header + '】\n  包含有校验值:\n 【' + expr + '】\n <-- 校验方式：Response Header ' + rules + ' -->'
            elif rules == '不包含':
                if type(expr) is str:
                    _isOK, expr = self.metfac.method_factory(method='Replacedata', data=expr)
                    headers = json.dumps(dict(headers), ensure_ascii=False)
                    print_header = json.dumps(json.loads(headers), sort_keys=True, indent=2, ensure_ascii=False)
                else:
                    print_header = headers
                try:
                    headers.index(expr)
                except Exception as e:
                    _isOk = True
                    _reason = '结果头:\n【' + print_header + '】\n  不包含校验值:\n 【' + expr + '】\n <-- 校验方式：Response Header ' + rules + ' -->'
                else:
                    _isOk = False
                    _reason = '结果头:\n【' + print_header + '】\n  包含有校验值:\n 【' + expr + '】\n <-- 校验方式：Response Header ' + rules + ' -->'
            elif rules == '等于':
                if type(expr) is str:
                    _isOK, expr = self.metfac.method_factory(method='Replacedata', data=expr)
                    headers = json.dumps(headers, ensure_ascii=False)
                    print_header = json.dumps(json.loads(headers), sort_keys=False, indent=4, ensure_ascii=False)
                else:
                    print_header = headers
                try:
                    if headers != expr:
                        raise Exception("校验不通过")
                except AssertionError as e:
                    _isOk = False
                    _reason = '结果头:\n【' + print_header + '】\n  不等于校验值:\n  【' + expr + '】\n <-- 校验方式：Response Header ' + rules + ' -->'
                else:
                    _isOk = True
                    _reason = '结果头:\n【' + print_header + '】\n  等于校验值:\n  【' + expr + '】\n <-- 校验方式：Response Header ' + rules + ' -->'

        elif(checktype == 1):
            try:
                res = reponse.json()
            except Exception:
                res = reponse.text

            if rules == '包含':
                if type(expr) is str:
                    _isOK, expr = self.metfac.method_factory(method='Replacedata', data=expr)
                    res = json.dumps(res, ensure_ascii=False)
                    print_result = json.dumps(json.loads(res), sort_keys=False, indent=4, ensure_ascii=False)
                else:
                    print_result = res
                try:
                    res.index(expr)
                except Exception as e:
                    _isOk = False
                    _reason = '结果:\n【' + print_result + '】\n  不包含校验值:\n  【' + expr + '】\n <-- 校验方式：Response Body ' + rules + ' -->'
                else:
                    _isOk = True
                    _reason = '结果:\n【' + print_result + '】\n  包含有校验值:\n  【' + expr + '】\n <-- 校验方式：Response Body ' + rules + ' -->'
            elif rules == '不包含':
                if type(expr) is str:
                    _isOK, expr = self.metfac.method_factory(method='Replacedata', data=expr)
                    res = json.dumps(res, ensure_ascii=False)
                    print_result = json.dumps(json.loads(res), sort_keys=False, indent=4, ensure_ascii=False)
                else:
                    print_result = res
                try:
                    res.index(expr)
                except Exception as e:
                    _isOk = True
                    _reason = '结果:\n【' + print_result + '】\n  不包含校验值:\n  【' + expr + '】\n <-- 校验方式：Response Body ' + rules + ' -->'
                else:
                    _isOk = False
                    _reason = '结果:\n【' + print_result + '】\n  包含有校验值:\n  【' + expr + '】\n <-- 校验方式：Response Body ' + rules + ' -->'
            elif rules == '等于':
                if type(expr) is str:
                    _isOK, expr = self.metfac.method_factory(method='Replacedata', data=expr)
                    res = json.dumps(res, ensure_ascii=False)
                    print_result = json.dumps(json.loads(res), sort_keys=False, indent=4, ensure_ascii=False)
                else:
                    print_result = res
                try:
                    if res != expr:
                        raise Exception("校验不通过")
                except Exception as e:
                    _isOk = False
                    _reason = '结果:\n【' + print_result + '】\n  不等于校验值:\n  【' + expr + '】\n <-- 校验方式：Response Body ' + rules + ' -->'
                else:
                    _isOk = True
                    _reason = '结果:\n【' + print_result + '】\n  等于校验值:\n  【' + expr + '】\n <-- 校验方式：Response Body ' + rules + ' -->'
            elif rules == '结果数据字段校验':
                res = json.dumps(res, ensure_ascii=False)
                print_result = json.dumps(json.loads(res), sort_keys=False, indent=4, ensure_ascii=False)

                if expr.find('<') < 0 and expr.find('>') < 0:
                    try:
                        if float(reponse.text) == float(expr):
                            _reason = '结果:\n【' + reponse.text + '】\n  不等于校验值:\n  【' + expr + '】'
                    except Exception as e:
                        _isOk = False
                        _reason = '结果数据字段校验失败，原因【' + str(e) + '】';
                elif expr.find('<') > 0:
                    if expr.find('<', expr.find('<') + 1, len(expr)) > 0:
                        expect = expr.split('<')
                        _isOk, result = self.metFac.method_factory(method='JSON结果取某字段列表', result=res, f_params=expect[1])
                        if _isOk is False:
                            return _isOk, result
                        i = 0
                        for item in result:
                            if float(item) > float(expect[0]) and float(item) < float(expect[2]):
                                i += 1
                            else:
                                break
                        if i == len(result):
                            _isOk = True
                            _reason = '结果:\n【' + print_result + '】\n  中的:\n  【' + expect[1] + '】的值都在【' + expect[
                                0] + ',' + expect[2] + '】之间'
                        else:
                            _isOk = False
                            _reason = '结果:\n【' + print_result + '】\n  中的:\n  【' + expect[1] + '】的值有不在【' + expect[
                                0] + ',' + expect[2] + '】之间的，值列表' + str(result)
                    else:
                        expect = expr.split('<')
                        _isOk, result = self.metfac.method_factory(method='JSON结果取某字段列表', result=res, f_params=expect[0])
                        if _isOk is False:
                            return _isOk, result
                        i = 0
                        for item in result:
                            if float(item) < float(expect[1]):
                                i += 1
                            else:
                                break
                        if i == len(result):
                            _isOk = True
                            _reason = '结果:\n【' + print_result + '】\n  中的:\n  【' + expect[0] + '】的值都小于【' + expect[
                                1] + '】'
                        else:
                            _isOk = False
                            _reason = '结果:\n【' + print_result + '】\n  中的:\n  【' + expect[0] + '】的值有大于【' + expect[
                                1] + '】的，值列表' + str(result)
                elif expr.find('>') > 0:
                    if expr.find('>', expr.find('>') + 1, len(expr)) > 0:
                        expect = expr.split('>')
                        _isOk, result = self.metfac.method_factory(method='JSON结果取某字段列表', result=res, f_params=expect[1])
                        if _isOk is False:
                            return _isOk, result
                        i = 0
                        for item in result:
                            if float(item) < float(expect[0]) and float(item) > float(expect[2]):
                                i += 1
                            else:
                                break
                        if i == len(result):
                            _isOk = True
                            _reason = '结果:\n【' + print_result + '】\n  中的:\n  【' + expect[1] + '】的值都在【' + expect[
                                0] + ',' + expect[2] + '】之间'
                        else:
                            _isOk = False
                            _reason = '结果:\n【' + print_result + '】\n  中的:\n  【' + expect[1] + '】的值有不在【' + expect[
                                0] + ',' + expect[2] + '】之间的，值列表' + str(result)
                    else:
                        expect = expr.split('>')
                        _isOk, result = self.metfac.method_factory(method='JSON结果取某字段列表', result=res, f_params=expect[0])
                        if _isOk is False:
                            return _isOk, result
                        i = 0
                        for item in result:
                            if float(item) > float(expect[1]):
                                i += 1
                            else:
                                break
                        if i == len(result):
                            _isOk = True
                            _reason = '结果:\n【' + print_result + '】\n  中的:\n  【' + expect[0] + '】的都大于【' + expect[1] + '】'
                        else:
                            _isOk = False
                            _reason = '结果:\n【' + print_result + '】\n  中的:\n  【' + expect[0] + '】的有小于【' + expect[
                                1] + '】的，值列表' + str(result)
        else:
            code = str(reponse.status_code)
            if rules == '等于':
                try:
                    if code != expr:
                        raise Exception("校验不通过")
                except Exception as e:
                    _isOk = False
                    _reason = '结果:\n【' + code + '】\n  不等于校验值:\n  【' + expr + '】\n <-- 校验方式：Status Code ' + rules + ' -->'
                else:
                    _isOk = True
                    _reason = '结果:\n【' + code + '】\n  等于校验值:\n  【' + expr + '】\n <-- 校验方式：Status Code ' + rules + ' -->'
            elif rules == '包含':
                try:
                    code.index(expr)
                except Exception as e:
                    _isOk = False
                    _reason = '结果:\n【' + code + '】\n  不等于校验值:\n  【' + expr + '】\n <-- 校验方式：Status Code ' + rules + ' -->'
                else:
                    _isOk = True
                    _reason = '结果:\n【' + code + '】\n  等于校验值:\n  【' + expr + '】\n <-- 校验方式：Status Code ' + rules + ' -->'
            elif rules == '不包含':
                try:
                    code.index(expr)
                except Exception as e:
                    _isOk = True
                    _reason = '结果:\n【' + code + '】\n  不等于校验值:\n  【' + expr + '】\n <-- 校验方式：Status Code ' + rules + ' -->'
                else:
                    _isOk = False
                    _reason = '结果:\n【' + code + '】\n  等于校验值:\n  【' + expr + '】\n <-- 校验方式：Status Code ' + rules + ' -->'
        return _isOk, _reason